#include "udev_include.h"

static struct udev *g_device_udev = NULL;
static struct udev_enumerate *g_device_iter = NULL;

typedef int (*device_matcher)(const char *, const device_t *);


static int match_device_syspath(const char *syspath, const device_t *device)
{
    const char *scsi_base_syspath = "/sys/devices/platform";  // NVMe Device
    const char *nvme_base_syspath = "/sys/devices/virtual";  // SCSI Device
    size_t scsi_path_len = strlen(scsi_base_syspath);
    size_t nvme_path_len = strlen(nvme_base_syspath);

    if (syspath == NULL) {
        return 0; 
    }
    if (strncmp(syspath, scsi_base_syspath, scsi_path_len) == 0) {
        return 1;
    }
    if (strncmp(syspath, nvme_base_syspath, nvme_path_len) == 0) {
        return 1;
    }
    return 0;
}

static int match_device_protocol(const char *syspath, const device_t *device)
{
    const char *sysname = NULL;

    if (device == NULL) {
        return 0; 
    }
    sysname = udev_device_get_sysname(device);
    if (sysname == NULL) {
        return 0; 
    }
    if (strncmp(sysname, "sd", strlen("sd")) == 0) {
        return 1;
    }
    if (strncmp(sysname, "nvme", strlen("nvme")) == 0) {
        return 1;
    }
    return 0;
}

static device_matcher g_matcher_list[] = {
    match_device_syspath,
    match_device_protocol,
};

static int match_device(const char *syspath, const device_t *device)
{
    int i = 0;
    int ret = 0;
    int matcher_num = sizeof(g_matcher_list) / sizeof(g_matcher_list[0]);

    for (i = 0; i < matcher_num; i++) {
        ret = g_matcher_list[i](syspath, device);
        if (ret == 0) {
            return 0;
        }
    }
    return 1;
}

static int udev_scan_start(void)
{
    int ret = 0;
    const char *syspath = NULL;
    const char *attr_value = NULL;
    const char *sysname = NULL;
    const char *protoname = NULL;
    device_t *device = NULL;
    struct udev_list_entry *entry = NULL;

    udev_enumerate_scan_devices(g_device_iter);
    printf("start\n");
    udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(g_device_iter)) {
        syspath = udev_list_entry_get_name(entry);
        if (syspath == NULL) {
            continue;
        }
        device = udev_device_new_from_syspath(g_device_udev, syspath);
        if (device == NULL) {
            continue;
        }
        ret = match_device(syspath, device);
        if (ret == 0) {
            udev_device_unref(device);
            continue; 
        }
        printf(" %s\n", syspath);
        udev_device_unref(device);
    }
    return 0;
}

static void udev_scan_release(void)
{
    if (g_device_iter != NULL) {
        udev_enumerate_unref(g_device_iter);
    }
    if (g_device_udev != NULL) {
        udev_unref(g_device_udev);
    }
}

static int udev_scan_init(void)
{
    int ret = -1;
    g_device_udev = udev_new();
    if (!g_device_udev) {
        printf("Failed to create udev\n");
        return -1;
    }
    g_device_iter = udev_enumerate_new(g_device_udev);
    if (g_device_iter == NULL) {
        udev_unref(g_device_udev);
        printf("Failed to create udev_iter\n");
        return -1;
    }
    ret = udev_enumerate_add_match_subsystem(g_device_iter, "block");
    if (ret != 0) {
        printf("Failed to add match subsystem\n");
        udev_scan_release();
        return -1;
    }
    ret = udev_enumerate_add_match_property(g_device_iter, "DEVTYPE", "disk");
    if (ret != 0) {
        printf("Failed to add match disk\n");
        udev_scan_release();
        return -1;
    }
    return 0;
}

int udev_scan_device(void)
{
    int ret = -1;
    ret = udev_scan_init();
    if (ret != 0) {
        printf("Failed to init udev\n");
        return -1;
    }
    ret = udev_scan_start();
    if (ret != 0) {
        printf("Failed to start udev\n");
        return -1;
    }
    udev_scan_release();
    return 0;
}
